﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OS;

namespace OS.Instructions
{
    class StoreRegister : Instruction
    {
        public StoreRegister()
        {
        }//end default constructor

        /// <summary>
        /// Executes the the SR instruction
        /// </summary>
        public override void ExecuteSRInstruction()
        {
            Trace.WriteToTrace("Executing SR instruction");

            int virtualAddress = int.Parse(QueueManager.readyQueue.Peek().register_IR[2].ToString() + QueueManager.readyQueue.Peek().register_IR[3].ToString());
            int page = virtualAddress / 10;

            if (QueueManager.readyQueue.Peek().TLB.ContainsKey(page))
            {
                //what type is it
                if (QueueManager.readyQueue.Peek().TLB[page] is Frame)
                {
                    int realAddress = UserStorage.VirtualToPhysical(virtualAddress, QueueManager.readyQueue.Peek().register_PTR);

                    //write it to the frame
                    Frame frm = (Frame)QueueManager.readyQueue.Peek().TLB[page];

                    int offset = virtualAddress % 10;
                    int slotInArr = offset * 4;

                    for(int i = 0; i < 4; i++)
                    {
                        frm.Data[slotInArr + i] = CPU.accumulator_R[i];
                    }

                    //write it to memory
                    UserStorage.WriteFrameToMemory(frm, (realAddress / 10) * 10);

                    Trace.WriteToTrace("Register R stored in " + realAddress);
                }
                else if (QueueManager.readyQueue.Peek().TLB[page] is Track)
                {
                    Track trk = (Track)QueueManager.readyQueue.Peek().TLB[page];

                    //swap
                    Trace.WriteToTrace("Need to swap track " + trk.TrackID + " into memory.");
                    Trace.WriteToTrace("Setting PI to 3 to request swap.");
                    CPU.PI = 3;
                }
            }
            //doesn't exist
            else if (QueueManager.readyQueue.Peek().frames < QueueManager.readyQueue.Peek().maxFrames)
            {
                //get new frame
                int frameNumber = EntryPoint.AllocateNewFrame(QueueManager.readyQueue.Peek());

                if (frameNumber != -1)
                {
                    //frame is available
                    Frame newlyAllocatedFrame = new Frame(frameNumber);
                    newlyAllocatedFrame.LastAccessed = EntryPoint.cycle;
                    Trace.WriteToTrace("Frame " + newlyAllocatedFrame.ID + " allocated.");

                    QueueManager.readyQueue.Peek().frames++;
                    Trace.WriteToTrace("Process " + QueueManager.readyQueue.Peek().groupID + " now has " + QueueManager.readyQueue.Peek().frames + " frames.");

                    //update TLB and page table
                    QueueManager.readyQueue.Peek().TLB[page] = newlyAllocatedFrame;
                    UserStorage.PhysicalMemory[QueueManager.readyQueue.Peek().register_PTR + page, 0] = newlyAllocatedFrame.ID.ToString();
                    Trace.WriteToTrace("Page table updated.");

                    int realAddress = UserStorage.VirtualToPhysical(virtualAddress, QueueManager.readyQueue.Peek().register_PTR);

                    UserStorage.PhysicalMemory[realAddress, 0] = CPU.accumulator_R[0].ToString();
                    UserStorage.PhysicalMemory[realAddress, 1] = CPU.accumulator_R[1].ToString();
                    UserStorage.PhysicalMemory[realAddress, 2] = CPU.accumulator_R[2].ToString();
                    UserStorage.PhysicalMemory[realAddress, 3] = CPU.accumulator_R[3].ToString();

                    Trace.WriteToTrace("Register R stored in " + realAddress);
                }
                else
                {
                    Console.WriteLine("StoreRegister.cs - no free frames");
                }
            }
            else
            {
                //move to swap queue
                Trace.WriteToTrace("Need to swap a frame out of memory.");
                Trace.WriteToTrace("Setting PI to 3 to request swap.");
                CPU.PI = 3;
            }

            CPU.SI = 0;

        }//end ExecuteInstruction
    }//end StoreRegister
}//end OS.Instruction
